using System;
using System.Collections;
using System.Collections.Generic;
using dnAnalytics.LinearAlgebra;
using NUnit.Framework;

namespace dnAnalytics.Tests.LinearAlgebra
{
    public abstract class VectorTest
    {
        protected static readonly double[] testArray = new[] {-1.1, -2.2, -3.3, 0, 1.1, 2.2};

        public abstract Vector GetVector(int order);
        public abstract Vector GetVector(int order, double value);
        public abstract Vector GetVector(double[] data);
        public abstract Matrix GetMatrix(int rows, int columns);

        [Test]
        public void EqualsTest()
        {
            Vector v = GetVector(testArray);
            Vector w = v;
            Vector u = GetVector(testArray);
            Assert.IsTrue(v.Equals(v));
            Assert.IsTrue(v.Equals(u));
            Assert.IsTrue(v.Equals(w));
            Assert.IsTrue(v.Equals(u) == u.Equals(v));
            Assert.IsTrue(v.Equals(w) == w.Equals(v));
            Assert.IsFalse(v.Equals(null));

            Assert.IsTrue(v == w);
            Assert.IsFalse(v != w);
            Assert.IsFalse(v == u);
            Assert.IsTrue(((IEquatable<Vector>) u).Equals(w));
            Assert.IsTrue(((IEquatable<Vector>) w).Equals(v));
        }

        [Test]
        public void AbsoluteMaximum()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            double expected = 3.3;
            double actual = target.AbsoluteMaximum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AbsoluteMaximumIndex()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            int expected = 2;
            int actual = target.AbsoluteMaximumIndex();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AbsoluteMinimum()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            double expected = 0;
            double actual = target.AbsoluteMinimum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AbsoluteMinimumIndex()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            int expected = 3;
            int actual = target.AbsoluteMinimumIndex();

            Assert.AreEqual(expected, actual);
        }

        [TestCase(0)]
        [TestCase(1)]
        [TestCase(2.2)]
        public void AddScalar(double scalar)
        {
            Vector vector = GetVector(testArray);
            vector.Add(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar + testArray[i], vector[i]);
            }
        }

        [Test]
        public void AddScalarResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            double scalar = 2.2;
            vector.Add(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar + testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddScalarResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Add(scalar, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddScalarResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            double scalar = 2.2;
            vector.Add(scalar, result);
        }


        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.Add(vector2);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddVectorNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            vector1.Add(vector2);
        }

        [Test]
        public void AddVectorResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length);
            vector1.Add(vector2, result);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] + testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddVectorResultNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = GetVector(testArray.Length);
            vector1.Add(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddVectorResultNull2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = null;
            vector1.Add(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddVectorResultNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            Vector result = GetVector(testArray.Length);
            vector1.Add(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddVectorResultNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            vector1.Add(vector2, result);
        }

        [Test]
        public void Plus()
        {
            Vector vector = GetVector(testArray);
            Vector result = vector.Plus();
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(+vector[i], result[i]);
            }
        }

        [Test]
        public void Clear()
        {
            Vector vector = GetVector(testArray);
            vector.Clear();
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(0, vector[i]);
            }
        }

        [Test]
        public void Clone()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Assert.AreEqual(vector1.Count, vector2.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i], vector2[i]);
            }
        }

        [Test]
        public void ICloneable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = (Vector) ((ICloneable) vector1).Clone();
            Assert.AreEqual(vector1.Count, vector2.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i], vector2[i]);
            }
        }

        [Test]
        public void CopyTo()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count);
            vector1.CopyTo(vector2);

            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i], vector2[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void CopyToNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.CopyTo(vector2);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void CopyToNotConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            vector1.CopyTo(vector2);
        }

        [Test]
        public void Count()
        {
            Vector vector = GetVector(testArray);
            Assert.AreEqual(testArray.Length, vector.Count);
        }

        [Test]
        public void Divide()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            vector.Divide(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i]/scalar, vector[i]);
            }
        }

        [Test]
        public void DivideResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            double scalar = 2.2;
            vector.Divide(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i]/scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void DivideResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Divide(scalar, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void DivideResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            double scalar = 2.2;
            vector.Divide(scalar, result);
        }


        [Test]
        public void DotProduct()
        {
            Vector vector = GetVector(6, 2);
            double result = vector.DotProduct();
            Assert.AreEqual(24, result);
        }

        [Test]
        public void DotProductVector()
        {
            Vector vector1 = GetVector(6, 2);
            Vector vector2 = GetVector(6, 2);
            double result = vector1.DotProduct(vector2);
            Assert.AreEqual(24, result);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void DotProductVectorNull()
        {
            Vector vector1 = GetVector(6, 2);
            Vector vector2 = null;
            vector1.DotProduct(vector2);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void DotProductVectorNotConformable()
        {
            Vector vector1 = GetVector(6, 2);
            Vector vector2 = GetVector(vector1.Count + 1, 2);
            vector1.DotProduct(vector2);
        }

        [Test]
        public void GetIndexedEnumerator()
        {
            Vector vector = GetVector(testArray);
            foreach (KeyValuePair<int, double> pair in vector.GetIndexedEnumerator())
            {
                Assert.AreEqual(testArray[pair.Key], pair.Value);
            }
        }

        [Test]
        public void GetEnumerator()
        {
            Vector vector = GetVector(testArray);
            int i = 0;
            foreach (double value in vector)
            {
                Assert.AreEqual(testArray[i++], value);
            }
        }

        [Test]
        public void IEnumerable()
        {
            Vector vector = GetVector(testArray);
            int i = 0;
            foreach (double value in ((IEnumerable) vector))
            {
                Assert.AreEqual(testArray[i++], value);
            }
        }

        [TestCase(1, 5)]
        [TestCase(1, 10, ExpectedException = typeof (ArgumentOutOfRangeException))]
        [TestCase(10, 20, ExpectedException = typeof (ArgumentOutOfRangeException))]
        public void GetEnumeratorRange(int start, int end)
        {
            Vector vector = GetVector(testArray);
            IEnumerator<KeyValuePair<int, double>> iterator = vector.GetEnumerator(start, end);

            int i = start;
            while (iterator.MoveNext())
            {
                KeyValuePair<int, double> pair = iterator.Current;
                // Check that the key (int) is in the range.
                Assert.AreEqual(i++, pair.Key);
                // Check that the value is the correct value
                Assert.AreEqual(testArray[pair.Key], pair.Value);
            }
        }


        [Test]
        public void InfinityNorm()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.InfinityNorm();
            double expected = 3.3;
            Assert.AreEqual(expected, actual);
        }

        [TestCase(1, 9.9)]
        [TestCase(2, 4.7948)]
        [TestCase(100, 3.3)]
        [TestCase(-1, 0, ExpectedException = typeof (ArgumentOutOfRangeException))]
        public void PNorm(int norm, double expected)
        {
            Vector vector = GetVector(testArray);
            Assert.AreEqual(expected, vector.PNorm(norm), .0001);
        }

        [TestCase(1)]
        [TestCase(2)]
        [TestCase(100)]
        [TestCase(-1, ExpectedException = typeof (ArgumentOutOfRangeException))]
        public void Normalize(int norm)
        {
            Vector vector = GetVector(testArray);
            Vector nvector = vector.Normalize(norm);
            Assert.AreEqual(1.0, nvector.PNorm(norm), .0001);
        }

        [Test]
        public void Maximum()
        {
            Vector vector = GetVector(testArray);

            double expected = 2.2;
            double actual = vector.Maximum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void MaximumIndex()
        {
            Vector vector = GetVector(testArray);

            int expected = 5;
            int actual = vector.MaximumIndex();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void Minimum()
        {
            Vector vector = GetVector(testArray);

            double expected = -3.3;
            double actual = vector.Minimum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void MinimumIndex()
        {
            Vector vector = GetVector(testArray);

            int expected = 2;
            int actual = vector.MinimumIndex();

            Assert.AreEqual(expected, actual);
        }

        [TestCase(0)]
        [TestCase(1)]
        [TestCase(2.2)]
        public void MultiplyScalar(double scalar)
        {
            Vector vector = GetVector(testArray);
            vector.Multiply(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i]*scalar, vector[i]);
            }
        }

        [TestCase(0)]
        [TestCase(1)]
        [TestCase(2.2)]
        public void MultiplyScalarResult(double scalar)
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            vector.Multiply(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i]*scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void MultiplyScalarResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Multiply(scalar, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void MultiplyScalarResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            double scalar = 2.2;
            vector.Multiply(scalar, result);
        }

        [Test]
        public void MultiplyVector()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = vector1.Multiply(vector2);
            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(testArray[i]*testArray[j], result[i, j]);
                }
            }

            Vector v = vector1*result;
            Vector w = result*vector1;
        }

        [Test]
        public void MultiplyVectorResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = GetMatrix(vector1.Count, vector2.Count);
            vector1.Multiply(vector2, result);

            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(testArray[i]*testArray[j], result[i, j]);
                }
            }
        }


        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void MultiplyVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.Multiply(vector2);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void MultiplyVectorResultMatrixIsNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = null;
            vector1.Multiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void MultiplyVectorResultVectorIsNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Matrix result = GetMatrix(vector1.Count, vector1.Count);
            vector1.Multiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void MultiplyVectorResultMatrixNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = GetMatrix(vector1.Count + 1, vector2.Count);
            vector1.Multiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void MultiplyVectorResultMatrixNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = GetMatrix(vector1.Count, vector2.Count + 1);
            vector1.Multiply(vector2, result);
        }


        [Test]
        public void Negate()
        {
            Vector vector = GetVector(testArray);
            vector.Negate();
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(-testArray[i], vector[i]);
            }
        }


        [Test]
        public void SetValues()
        {
            Vector vector = GetVector(testArray.Length);
            vector.SetValues(testArray);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i], vector[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void SetValuesNull()
        {
            Vector vector = GetVector(testArray.Length);
            vector.SetValues(null);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void SetValuesNotConformable()
        {
            Vector vector = GetVector(testArray.Length + 1);
            vector.SetValues(testArray);
        }

        [Test]
        public void SubtractScalar()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            vector.Subtract(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] - scalar, vector[i]);
            }
        }

        [Test]
        public void SubtractScalarResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            double scalar = 2.2;
            vector.Subtract(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] - scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void SubtractScalarResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Subtract(scalar, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void SubtractScalarResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length - 1);
            double scalar = 2.2;
            vector.Subtract(scalar, result);
        }

        [Test]
        public void SubtractVector()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            vector1.Subtract(vector2);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] - testArray[i], vector1[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void SubtractVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.Subtract(vector2);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void SubtractVectorNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length - 1);
            vector1.Subtract(vector2);
        }

        [Test]
        public void SubtractVectorResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length);
            vector1.Subtract(vector2, result);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] - testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void SubtractVectorResultNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = GetVector(testArray.Length);
            vector1.Subtract(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void SubtractVectorResultNull2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            vector1.Subtract(vector2, null);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void SubtractVectorResultNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length - 1);
            Vector result = GetVector(testArray.Length);
            vector1.Subtract(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void SubtractVectorResultNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length - 1);
            vector1.Subtract(vector2, result);
        }

        [TestCase(0, 5)]
        [TestCase(0, 6)]
        [TestCase(2, 2)]
        [TestCase(1, 4)]
        [TestCase(6, 10, ExpectedException = typeof (ArgumentOutOfRangeException))]
        [TestCase(1, 10, ExpectedException = typeof (ArgumentOutOfRangeException))]
        public void SubVector(int start, int length)
        {
            Vector vector = GetVector(testArray);

            Vector sub = vector.GetSubVector(start, length);
            Assert.AreEqual(length, sub.Count);
            for (int i = 0; i < length; i++)
            {
                Assert.AreEqual(vector[i + start], sub[i]);
            }
        }

        [Test]
        public void Sum()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.Sum();
            double expected = 0;
            for (int i = 0; i < testArray.Length; i++)
            {
                expected += testArray[i];
            }
            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void SumMagnitudes()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.SumMagnitudes();
            double expected = 0;
            for (int i = 0; i < testArray.Length; i++)
            {
                expected += System.Math.Abs(testArray[i]);
            }
            Assert.AreEqual(expected, actual, Constants.AcceptableError);
        }

        [Test]
        public void Item()
        {
            Vector vector = GetVector(testArray.Length);
            for (int i = 0; i < testArray.Length; i++)
            {
                vector[i] = testArray[i];
                Assert.AreEqual(testArray[i], vector[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (IndexOutOfRangeException))]
        public void ItemIndexOutOfRange1()
        {
            Vector vector = GetVector(1);
            vector[-1] = 1;
        }

        [Test]
        [ExpectedException(typeof (IndexOutOfRangeException))]
        public void ItemIndexOutOfRange2()
        {
            Vector vector = GetVector(1);
            vector[2] = 1;
        }

        [Test]
        public void ToArray()
        {
            Vector vector = GetVector(testArray);
            double[] temp = vector.ToArray();
            Assert.AreEqual(vector.Count, temp.Length);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i], temp[i]);
            }
        }


        [Test]
        public void OperatorSubtract()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = vector1 - vector2;
            Assert.AreEqual(vector1.Count, result.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i] - vector2[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorSubtractNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = vector1 - vector2;
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorSubtractNull2()
        {
            Vector vector1 = null;
            Vector vector2 = GetVector(testArray);
            Vector result = vector1 - vector2;
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void OperatorSubtractVectorVectorNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count + 1);
            Vector result = vector1 - vector2;
        }

        [Test]
        public void OperatorNegate()
        {
            Vector vector = GetVector(testArray);
            Vector result = -vector;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(-vector[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorNegateNull()
        {
            Vector vector = null;
            vector = -vector;
        }

        [Test]
        public void OperatorAdd()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = vector1 + vector2;
            Assert.AreEqual(vector1.Count, result.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i] + vector2[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorAddNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = vector1 + vector2;
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorAddNull2()
        {
            Vector vector1 = null;
            Vector vector2 = GetVector(testArray);
            Vector result = vector1 + vector2;
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void OperatorAddNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count + 1);
            Vector result = vector1 + vector2;
        }

        [Test]
        public void OperatorPlus()
        {
            Vector vector = GetVector(testArray);
            Vector result = +vector;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(+vector[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorPlusNull()
        {
            Vector vector = null;
            vector = +vector;
        }

        [Test]
        public void OperatorMultiplyScalarVector()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            Vector result = scalar*vector;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar*testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorMultiplyScalarVectorNull()
        {
            Vector vector = null;
            double scalar = 2.2;
            Vector result = scalar*vector;
        }

        [Test]
        public void OperatorMultiplyVectorScalar()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            Vector result = vector*scalar;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(vector[i]*scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorMultiplyVectorNullScalar()
        {
            Vector vector = null;
            double scalar = 2.2;
            Vector result = vector*scalar;
        }

        [Test]
        public void OperatorMultiply()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = vector1*vector2;
            Assert.AreEqual(vector1.Count, result.Rows);
            Assert.AreEqual(vector2.Count, result.Columns);
            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(vector1[i]*vector2[j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorMultiplyNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Matrix result = vector1*vector2;
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorMultiplyNull2()
        {
            Vector vector1 = null;
            Vector vector2 = GetVector(testArray);
            Matrix result = vector1*vector2;
        }

        [Test]
        public void OperatorDivide()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            Vector result = vector/scalar;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(vector[i]/scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void OperatorDivideNull()
        {
            Vector vector = null;
            double scalar = 2.2;
            Vector result = vector/scalar;
        }

        [Test]
        public void AddScaledVectorSelf()
        {
            double factor = 5;
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            vector1.AddScaledVector(factor, vector2);

            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] + factor*testArray[i], vector1[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddScaledVectorSelfNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.AddScaledVector(10, vector2);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddScaledVectorSelfNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            vector1.AddScaledVector(10, vector2);
        }

        [Test]
        public void AddScaledVectorResult()
        {
            double factor = 5;
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length);
            vector1.AddScaledVector(factor, vector2, result);

            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] + factor*testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddScaledVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = GetVector(testArray.Length);
            vector1.AddScaledVector(10, vector2, result);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void AddScaledVectorResultNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length);
            Vector result = null;
            vector1.AddScaledVector(10, vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddScaledVectorNotConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            Vector result = GetVector(testArray.Length);
            vector1.AddScaledVector(10, vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void AddScaledVectorResultNotConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length);
            Vector result = GetVector(testArray.Length + 1);
            vector1.AddScaledVector(10, vector2, result);
        }

        [Test]
        public void PointwiseMultiplyResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length);
            vector1.PointwiseMultiply(vector2, result);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i]*testArray[i], result[i]);
            }

            result = vector1.PointwiseMultiply(vector2);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i]*testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void PointwiseMultiplyNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = GetVector(testArray.Length);
            vector1.PointwiseMultiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void PointwiseMultiplyResultNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            vector1.PointwiseMultiply(vector2, null);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void PointwiseMultiplyNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            Vector result = GetVector(testArray.Length);
            vector1.PointwiseMultiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof (NotConformableException))]
        public void PointwiseMultiplyNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length);
            Vector result = GetVector(testArray.Length + 1);
            vector1.PointwiseMultiply(vector2, result);
        }

        [Test]
        public void ToStringTest()
        {
            Vector vector = GetVector(testArray);
            string expected = "-1.1, -2.2, -3.3, 0, 1.1, 2.2";
            Assert.IsTrue(expected.Equals(vector.ToString()));
            Assert.IsTrue(expected.Equals(vector.ToString((string) null)));
            Assert.IsTrue(expected.Equals(vector.ToString((IFormatProvider) null)));
            Assert.IsTrue(expected.Equals(vector.ToString(null, null)));
            expected = "-1.10, -2.20, -3.30, 0.00, 1.10, 2.20";
            Assert.IsTrue(expected.Equals(vector.ToString("N")));
        }

        [TestCase(0, 0, 6)]
        [TestCase(5, 5, 1)]
        [TestCase(1, 4, 2)]
        [TestCase(4, 1, 2)]
        [TestCase(6, 0, 6, ExpectedException = typeof (ArgumentOutOfRangeException))]
        [TestCase(0, 6, 6, ExpectedException = typeof (ArgumentOutOfRangeException))]
        [TestCase(0, 0, 7, ExpectedException = typeof (ArgumentOutOfRangeException))]
        [TestCase(4, 0, 3, ExpectedException = typeof (ArgumentOutOfRangeException))]
        [TestCase(0, 4, 3, ExpectedException = typeof (ArgumentOutOfRangeException))]
        public void CopyToTest(int srcOffest, int dstOffest, int count)
        {
            Vector vector = GetVector(testArray);
            Vector other = GetVector(testArray.Length);
            vector.CopyTo(other, srcOffest, dstOffest, count);
            for (int i = 0; i < count; i++)
            {
                Assert.AreEqual(vector[srcOffest + i], other[dstOffest + i]);
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void CopyToNullTest()
        {
            Vector vector = GetVector(testArray);
            vector.CopyTo(null, 0, 0, vector.Count);
        }

        [Test]
        public void SubtractZero()
        {
            Vector vector = GetVector(testArray);
            vector.Subtract(0);
            Vector test = GetVector(testArray);

            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(test[i], vector[i]);
            }
        }

        [Test]
        public void Add_ResultSameObject()
        {
            Vector vector = GetVector(testArray);
            vector.Add(vector, vector);
            Vector test = GetVector(testArray);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(test[i] + test[i], vector[i]);
            }
        }

        [Test]
        public void Subtract_ResultSameObject()
        {
            Vector vector = GetVector(testArray);
            vector.Subtract(vector, vector);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(0, vector[i]);
            }
        }

        [Test]
        public void CopyTo_SameObject()
        {
            Vector vector = GetVector(testArray);
            Vector test = GetVector(testArray);
            vector.CopyTo(vector);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(test[i], vector[i]);
            }
        }

        [Test]
        public void CopyTo_SameObject_Indexed()
        {
            Vector vector = GetVector(testArray);
            Vector test = GetVector(testArray);
            vector.CopyTo(vector, 0, 0, vector.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(test[i], vector[i]);
            }
        }

        [Test]
        public void Equals_NonVector_ReturnsFalse()
        {
            Vector vector = GetVector(testArray);
            Assert.IsFalse(vector.Equals(2));
        }

        [Test]
        public void Equals_DifferentSize_ReturnsFalse()
        {
            Vector vector1 = GetVector(5);
            Vector vector2 = GetVector(4);
            Assert.IsFalse(vector1.Equals(vector2));
        }

        [Test]
        public void Equals_DifferentValues_ReturnsFalse()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(4);
            Assert.IsFalse(vector1.Equals(vector2));
        }

        [Test]
        public void VectorGetHashCode()
        {
            Vector vector = GetVector(new double[] {1, 2, 3, 4});
            Assert.AreEqual(2145910784, vector.GetHashCode());
        }
    }
}